--[[
each record representation one request/response
--]]
local specification = require('specification')
local struct = require('struct')
local structMapper = {
  ending = '>',
  int = "i",
  long = "l",
  buffer = "S",
  boolean = "B",
  ustring = "S"
}


local _M = {}
_M.__index = _M

_M.OP_CODES = {
  NOTIFICATION = 0,
  CREATE = 1,
  DELETE = 2,
  EXISTS = 3,
  GET_DATA = 4,
  SET_DATA = 5,
  GET_ACL = 6,
  SET_ACL = 7,
  GET_CHILDREN = 8,
  SYNC = 9,
  PING = 11,
  GET_CHILDREN2 = 12,
  CHECK = 13,
  MULTI = 14,
  AUTH = 100,
  SET_WATCHES = 101,
  SASL = 102,
  CREATE_SESSION = -10,
  CLOSE_SESSION = -11,
  ERROR = -1
}

--[[
Record = {
    protocol = "xx" ,
    headers = { k1=v1, k2=v2},
    payload = { kn = vn},
    stream = {} ,   byteArray
}
constructor = function (protocol)

methods function setHeaderAttr(key,value)
methods function setPayloadAttr(key,value)

--]]
local isDebug = false
function _M:new(protocol, header, payload)
  local request = {
    protocol = protocol,
    header = header,
    payload = payload
  }
  return setmetatable(request, self)
end

--
function _M:setHeader(header)
  self.header = header
end

--
function _M:setPayload(payload)
  self.payload = payload
end


-- parse data to byte array for sending
function _M:toStream()
  -- header to bytes
  -- payload to bytes
  -- get length
  -- combine
  local headerStream
  if self.header ~= nil then
    headerStream = self:getHeaderStream()
    if isDebug then
      print('toStream, header len=' .. #headerStream)
    end
  end

  local payloadStream = self:getPayloadStream()

  local len = #payloadStream
  if isDebug then
    print('toStream, payload len=' .. #payloadStream)
  end
  if headerStream then len = len + #headerStream end


  local tmp = {}
  table.insert(tmp, simpleMapper('>i', len))
  if headerStream then
    table.insert(tmp, headerStream)
  end
  table.insert(tmp, payloadStream)

  return table.concat(tmp)
end

--[[
    { name = "xid", type = "int" },
    { name = "type", type = "int"}
--]]
function _M:getHeaderStream()
  return struct.pack('>ii', self.header.xid, self.header.type)
end

function simpleMapper(type, value)
  return struct.pack(type, value)
end


function _M:getPayloadStream()
  local tmp = {}
  local protocol = specification.protocol[self.protocol] -- table { {name=xx, type=xx}, {..}}4

  for _, nameType in pairs(protocol) do
    local name = nameType.name
    local value = self.payload[name]
    local type = nameType.type
    if structMapper[type] ~= nil then
      -- direct map is good
      table.insert(tmp, simpleMapper('>' .. structMapper[type], value))
    elseif "vector<ustring>" == type then
      table.insert(tmp, simpleMapper('>i', #value)) -- int >i
      for _, ustr in pairs(value) do
        table.insert(tmp, simpleMapper('>S', ustr)) -- buffer/ustring >S
      end
    elseif "vector<vector<data.ACL>" == type then
      error('not support type=' .. type) -- TODO will be supported
    else
      error('not support type=' .. type)
    end
  end

  return table.concat(tmp)
end

function payloadToStream(protocolType, payload)
end

-- 构建多个请求
function _M:multiRequst(reqsTbl)
  for _, req in iparis(reqsTbl) do
    if req.type == request.OP_CODES.GET_CHILDREN2 then
    else
      error("not support muti requst code:" .. req.type)
    end
  end
end

return _M